/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.javahispano.javacup.tacticas_aceptadas.maxtor.org.javahispano.javacup.modelo.mio.servicios;

import java.util.*;

import org.javahispano.javacup.modelo.*;
import org.javahispano.javacup.tacticas_aceptadas.maxtor.org.javahispano.javacup.modelo.mio.*;

/**
 * 
 * @author Administrador
 */
public class UtilEvaluador {

	public static double MAX_ANGULO_PASE = Math.PI / 2;
	
	private static double LATERAL_DISTANCIABALON_AVANZAR = 45;
	private static int CENTRAL_NUM_RIVALESADELANTADOS_CUBRIR = 2;
	private static double METROSAVANCE = 15;
	private static int TURNOS_MINIMO_INTERCEP = 25;
	
	public static int[] INDICE_CENTRALES = {2,3};
    public static int[] INDICE_LATERALES = {1,4};
    
        public static double DISTANCIA_ALEJAMIENTO_COBERTURA = 25;
	

	public static Collection getIndicesDesmarcados(Posicion balon, Posicion[] misJugadores,
			Posicion[] rivales) {
		ArrayList desmarcados = new ArrayList();
		
	//	desmarcados.add(new Integer((int)(Math.random()*10)));
//		return desmarcados;
		
		//for (int i = 0; i < misJugadores.length; i++) {
			int[] iCercanos = balon.indicesMasCercanos(misJugadores);
			// System.out.println("INDICE MAS CERCANO "+iCercano);
//			if (iCercano < 0) {
//				System.out.println("UTILEV INDICE MAS CERCANO -1: " + misJugadores[i]);
//				return null;
//			}
			//if (rivales[iCercano].distancia(misJugadores[i]) > IEvaluadorService.DISTANCIA_DESMARQUE)
			//	desmarcados.add(new Integer(i));
			for (int i = 0; i < 6; i++) {
				desmarcados.add(new Integer(iCercanos[i]));
			}
		//}
		return desmarcados;
		
	}

	
    // -------------------- PASE -------------------------------

	public static void getCirculosControlPase(ArrayList<Circulo> lista,
			Pase pase, Posicion[] misJugadores) {
		if (lista == null)
			return;
		Posicion pasador = misJugadores[pase.getIndicePasador()];
		Posicion receptor = misJugadores[pase.getIndiceReceptor()];
		Circulo circuloControl = new Circulo();
		circuloControl.setCentro(receptor);
		circuloControl.radio = Constantes.DISTANCIA_CONTROL_BALON;
		Circulo circuloPase = new Circulo();
		circuloPase.setCentro(pasador);
		getIteracionesPase(circuloControl, circuloPase, pase.getReceptor(), pase.getPasador(), pase.getFactorRiesgo());
		lista.add(circuloControl);
		lista.add(circuloPase);
	}

	private static Collection getPuntosRecepcionDespejados(Pase pase,
			Posicion[] misJugadores, Posicion[] rivales,
			JugadorDetalle[] detalleMisJugadores , JugadorDetalle[] detalleRivales) {
		
		Posicion pasador = misJugadores[pase.getIndicePasador()];
		Posicion receptor = misJugadores[pase.getIndiceReceptor()];
		Circulo circuloControl = new Circulo();
		circuloControl.setCentro(receptor);
		circuloControl.radio = Constantes.DISTANCIA_CONTROL_BALON;
		Circulo circuloPase = new Circulo();
		circuloPase.setCentro(pasador);

		int iteracionesPase = getIteracionesPase(circuloControl, circuloPase,
				pase.getReceptor(), pase.getPasador(), pase.getFactorRiesgo());
		pase.setIteraciones(iteracionesPase);

		Collection<Posicion> puntosRecepcion = new ArrayList<Posicion>();
                
                double velocidadRemate = getVelocidadRemate(detalleMisJugadores[pase.getIndicePasador()]);
                double velocidadReceptor = getVelocidadJugador(detalleMisJugadores[pase.getIndiceReceptor()]);
                
		for (int pasos=0;pasos<5; pasos++) 
		{
			Posicion[] intersecciones = UtilGeometria.getInterseccionCirculosAprox(circuloPase, circuloControl);

                        if (intersecciones==null) continue;
                        
			int[] indicesCercanos = receptor.indicesMasCercanos(rivales);

                        boolean isDespejado0 = true;
                        boolean isDespejado1 = true;
			for (int i : indicesCercanos) {
				
				Posicion punto = intersecciones[0];
				int indiceRival = indicesCercanos[i]; 
				double velocidad = getVelocidadJugador(detalleRivales[indiceRival]);
				if (!isDespejado(velocidad, iteracionesPase+pasos, punto, rivales[indiceRival]))
					isDespejado0 = false;
                                
				punto = intersecciones[1];
				if (!isDespejado(velocidad, iteracionesPase+pasos, punto, rivales[indiceRival]))
					isDespejado1 = false;
				
				
			}
                        if (isDespejado0) puntosRecepcion.add(intersecciones[0]);
                        if (isDespejado1) puntosRecepcion.add(intersecciones[1]);
                        circuloPase.radio+=velocidadRemate;
                        circuloControl.radio+=velocidadReceptor;
		}
		return puntosRecepcion;
	}

	private static boolean isDespejado(double velocidad, int iteracionesPase, Posicion punto, Posicion posicionRival) {
		
		double radioAccionRival = ( velocidad * iteracionesPase ) + Constantes.DISTANCIA_CONTROL_BALON;
		double distancia = posicionRival.distancia(punto);
		return (distancia > radioAccionRival);
	}
	
	private static int getIteracionesPase(Circulo circuloControl,
			Circulo circuloPase, JugadorDetalle receptor, JugadorDetalle pasador, double factorRiesgo) {

		double velocidadReceptor = getVelocidadJugador(receptor);
		double velocidadRemate = getVelocidadRemate(pasador);
		
		for (int iteraciones = 0; iteraciones < IEvaluadorService.MAX_ITERACIONES; iteraciones++) {
			
			circuloControl.radio += velocidadReceptor;
			circuloPase.radio += velocidadRemate;
			velocidadRemate *= Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
			if (iteraciones >= IEvaluadorService.MIN_ITERACIONES) {
				if (UtilGeometria.hayColision(circuloPase, circuloControl)) {
					circuloControl.radio += velocidadReceptor*2;
					circuloPase.radio += velocidadRemate*2;
					return iteraciones + 2; //..a�adimos +2 extra por las imprecisiones del pase
				}
			}
		}
		return 0;
	}
	private static double getVelocidadJugador(JugadorDetalle jugador) {
		return Constantes.getVelocidad(jugador.getVelocidad());
	}
	private static double getVelocidadRemate(JugadorDetalle jugador){
		return 1 * Constantes.getVelocidadRemate(jugador.getRemate());//calcula la velocidad del remate
	}
	
	
	public static Collection<Pase> getPases(Collection circulosPase,
			Collection desmarcados, int[] puedenRematar,
			Posicion[] misJugadores, JugadorDetalle[] detalleMisJugadores,
			Posicion[] rivales, JugadorDetalle[] detalleRivales) {

		Collection<Pase> pases = new ArrayList<Pase>();
		
		for (int indicePasador : puedenRematar) {

			JugadorDetalle detallePasador = detalleMisJugadores[indicePasador];

			Iterator iter = desmarcados.iterator();
			while (iter.hasNext()) {
				
			
				int indiceReceptor = ((Integer) iter.next()).intValue();
				if (indiceReceptor == indicePasador)
					continue; // es el mismo jugador

				JugadorDetalle detalleReceptor = detalleMisJugadores[indiceReceptor];

				Pase pase = new Pase();
				pase.setIndicePasador(indicePasador);
				pase.setIndiceReceptor(indiceReceptor);
				pase.setPasador(detallePasador);
				pase.setReceptor(detalleReceptor);
				pase.setFactorRiesgo(UtilEvaluador.getFactorRiesgo());

				UtilEvaluador.getCirculosControlPase((ArrayList<Circulo>) circulosPase, pase, misJugadores);
				Collection puntosRecepcion = UtilEvaluador.getPuntosRecepcionDespejados(pase, misJugadores,
								rivales, detalleMisJugadores, detalleRivales);
				if (puntosRecepcion != null) {
					pase.setPuntosRecepcion(puntosRecepcion);
					pases.add(pase);
				}

			}
		}
		return pases;
	}
	
	
	 public static Pase seleccionarPase(Collection<Pase> listaPases, Posicion posicionBalon, Posicion[] posicionMisJugadores, Posicion[] posicionRivales,
	    		JugadorDetalle[] detalleMisJugadores, JugadorDetalle[] detalleRivales, Posicion posicionPorteria) {
	  
	        Pase paseSeleccionado = null;
	        Posicion puntoSeleccionado = null;
	        Iterator iter = listaPases.iterator();
	        double distanciaSeleccionada = 1000;
	        double distancia = 0;
	        while (iter.hasNext()) {
	            Pase pase = (Pase)iter.next();
	            Iterator recepciones = pase.getPuntosRecepcion().iterator();
	            while(recepciones.hasNext()) {
	                Posicion punto = (Posicion)recepciones.next();
	                distancia = posicionPorteria.distancia(punto);
	                if (distancia<distanciaSeleccionada) {
	                    distanciaSeleccionada = distancia;
	                    paseSeleccionado = pase;
	                    puntoSeleccionado = punto;
	                }
	            }
	        }
	        if (puntoSeleccionado==null) return null;
	        paseSeleccionado.setPuntoSeleccionado(puntoSeleccionado);
	        return paseSeleccionado;
	    }
	 
	 
	 
	private static double getFactorRiesgo() {
		return 0.5;
	}
	
	

    
    public static Collection<Disparo> getDisparos(Posicion rematador, int indiceRematador, JugadorDetalle detalleRematador, Posicion portero, JugadorDetalle detallePortero, Posicion[] defensas, JugadorDetalle detalleDefensas) {
        ArrayList<Disparo> disparos = new ArrayList<Disparo>();
        
        Posicion paloIzq = Constantes.centroArcoSup.moverPosicion(-Constantes.LARGO_ARCO/2, 0);
        Posicion paloDer = Constantes.centroArcoSup.moverPosicion(+Constantes.LARGO_ARCO/2, 0);
        
        double distancia = Constantes.centroArcoSup.distancia(rematador);
        Disparo disparo = new Disparo();
        boolean hayDisparo = disparo.set(distancia, detalleRematador);
        if (hayDisparo) {
            disparo.setIndiceRematador(indiceRematador);
            disparo.setAnguloRemateHorizontal(Constantes.centroArcoSup.angulo(rematador));
            disparos.add(disparo);
        }
        
        return disparos;
    }
    
    // -------------------- MOVIMIENTO -------------------------------
    
    
    public static Posicion[] getIntercepcionesBalon(VectorFis balon, Posicion[] misJugadores, JugadorDetalle[] detalleMisJugadores){
    	double[] factorDisminucion = new double[3];
    	factorDisminucion[0] = factorDisminucion[1] = Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
    	//TODO factor disminucion
    	factorDisminucion[2] = Constantes.G;
    	
    	Posicion[] intercepciones = new Posicion[11];
    	Circulo [] radiosAccion = new Circulo[11];
    	for (int i=0;i<11;i++) {
    		Circulo circulo = new Circulo();
    		circulo.setCentro(misJugadores[i]);
    		circulo.radio = Constantes.DISTANCIA_CONTROL_BALON;  
    		radiosAccion[i] = circulo;
    	}
    	int count = 0;
    	for (int iter=2; iter<IEvaluadorService.MAX_ITERACIONES; iter++) {
    		// comienza en 2 porque la simluacion de 1 es la actual 
    		double[] destinoBalon = balon.simular(iter,factorDisminucion);
    		Posicion destino = new Posicion(destinoBalon[0], destinoBalon[1]);
    		for (int i=0;i<11;i++) {
    			if (intercepciones[i] == null) {
    				radiosAccion[i].radio += Constantes.getVelocidad(detalleMisJugadores[i].getVelocidad());
    				double distanciaIntercepcion = destino.distancia(misJugadores[i]);
    				if (radiosAccion[i].radio > distanciaIntercepcion) { // caza el balon
    					intercepciones[i] = new Posicion(destino);
    					count ++;
    					if (count>10) break;
    				}
    			}
    		}
    	}
    	return intercepciones;
    }
    
    
    public static Posicion[] getMovimientoGeneral(Posicion[] misJugadores, Posicion[] rivales, 
    		JugadorDetalle[] detalleMisJugadores, JugadorDetalle[] detalleRivales, 
    		Posicion[] intercepciones, Posicion[] intercepcionesRival, 
    		VectorFis vectorBalon, boolean atacando, DatosPartido datos, int[] iteraciones) 
    {
    	Posicion[] movimientos = new Posicion[11];
    	

        
    	ArrayList<JugadorComparable> jugadores = new ArrayList<JugadorComparable>();
    	
    	for (int i=0;i<11;i++) {
    		if (intercepciones[i]!=null) jugadores.add( new JugadorComparable( getTurnosIntercepcion(misJugadores[i], intercepciones[i], detalleMisJugadores[i]), i, true));
    		if (intercepcionesRival[i]!=null) jugadores.add( new JugadorComparable( getTurnosIntercepcion(rivales[i], intercepcionesRival[i], detalleRivales[i]), i, false));
    	}
    	Collections.sort(jugadores);
    	
    	if (jugadores.size()==0) return movimientos;
    	
    	JugadorComparable primero = jugadores.get(0);
    	
    	if (primero.isMio()){
    		 
    		JugadorDetalle detallePrimero = detalleMisJugadores[primero.getDorsal()];
			double alturaControl = detallePrimero.esPortero()?Constantes.ALTO_ARCO:Constantes.ALTURA_CONTROL_BALON;
			boolean arrastra = vectorBalon.getDestino()[2]==0;
			double [] factorDisminucion = new double[3]; 
	    	factorDisminucion[0] = factorDisminucion[1] = arrastra?Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO:Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
	    	factorDisminucion[2] = arrastra?0:Constantes.G;
    	    	
	    	double[] simulacion = vectorBalon.simular(primero.getTurno(), factorDisminucion);
    	    	// si controlo el balon voy a por el
	    	if (Math.abs(simulacion[2])<=alturaControl)
	    		movimientos[primero.getDorsal()] = intercepciones[primero.getDorsal()];
    		
    	} 
	    	for (int i=0;i<jugadores.size();i++) {
	    		JugadorComparable jugador = jugadores.get(i);
	    		if (jugador.isMio()){
	    			int dorsal = jugador.getDorsal();
//	    			 if (detalleMisJugadores[dorsal].esPortero()) continue;
	    			if (jugador.getTurno() <= primero.getTurno()){
	    				// ..cubro el punto de intercepcion del primero
	    				movimientos[dorsal] = intercepciones[primero.getDorsal()];
	    				
	    			} else if (jugador.getTurno() < TURNOS_MINIMO_INTERCEP) {
	    				//	..voy a por el balon
	    				movimientos[dorsal] = intercepciones[dorsal];
	    			} 
	    		}; 
	
	    	}
    		
	    	if (intercepciones[primero.getDorsal()]!=null) {
	    		int indiceMasCercano = intercepciones[primero.getDorsal()].indiceMasCercano(misJugadores);
	    		movimientos[indiceMasCercano] = intercepciones[primero.getDorsal()];
	    	}
    	

  
    	return movimientos;
    }
    
    
    
    private static Integer getTurnosIntercepcion(Posicion jugador, Posicion puntoIntercepcion, JugadorDetalle detalle) {
	    double distancia = jugador.distancia(puntoIntercepcion);
		double velocidad = getVelocidadJugador(detalle);
		return new Integer((int)Math.ceil(
				(distancia - 
					(detalle.esPortero() ? Constantes.DISTANCIA_CONTROL_BALON_PORTERO : Constantes.DISTANCIA_CONTROL_BALON)
							)/velocidad));
    }
    public static Posicion getMovimientoPortero(Posicion balon) {
    	double 	max = Math.min(balon.getX(), 3);
        		max = Math.max(max, -3);
        double miny = Math.min(balon.getY(), Constantes.centroArcoInf.getY()+3);
        return new Posicion(max, miny);
    }
    
    public static Posicion getMovimientoPasador(Posicion pasador, Posicion destinoBalon, Posicion[] rivales) {
    	int[] rivalesMasCercanosPasador = pasador.indicesMasCercanos(rivales);
    	double angulo = destinoBalon.angulo(rivales[rivalesMasCercanosPasador[0]]);
    	if (angulo>180) angulo = -angulo;
    	return pasador.moverAngulo(angulo, METROSAVANCE);
    }
    
    public static Posicion[] getMovimientoCentrales(int[] indiceCentrales, Posicion[] misJugadores, Posicion[] rivales, Posicion balon) {
    	
    	Posicion [] movimientos = new Posicion[11];
    	
    	int[] indiceRivalesAdelantados = Constantes.centroArcoInf.indicesMasCercanos(rivales);
    	double [] distanciaRivales = new double[CENTRAL_NUM_RIVALESADELANTADOS_CUBRIR];
    	
    	for (int i=0;i<distanciaRivales.length;i++) distanciaRivales[i] = 1000;
    	    	
    	for (int i=0;i<indiceCentrales.length;i++) {
            Posicion central = misJugadores[i];
            int indiceRival = indiceRivalesAdelantados[i];
            Posicion rival = rivales[indiceRival];
            double distancia = Constantes.penalInf.distancia(central); 
            if (distancia<DISTANCIA_ALEJAMIENTO_COBERTURA)
                movimientos[indiceCentrales[i]] = getPosicionCubrir(rival,balon);
    	}
    	
    	return movimientos;
    }
    
    public static Posicion[] getMovimientoLaterales(int[] indiceLaterales, boolean atacando, Posicion balon, Posicion[] misJugadores, Posicion[] rivales) {
    	Posicion [] movimientos = new Posicion[11];
    	
    	if (atacando) { //avanzo por mi carril
    		for (int i: indiceLaterales) {
    			Posicion lateral = misJugadores[i];
    			if (lateral.distancia(balon) < LATERAL_DISTANCIABALON_AVANZAR){
    				double destinox = Constantes.centroCampoJuego.getX() + (i==0?-1:1) * Constantes.ANCHO_CAMPO_JUEGO/2;
    				double dx = destinox  - lateral.getX();
    				movimientos[i] = lateral.moverPosicion(dx, METROSAVANCE);
    			}
    		}
    	} else { //cubrir lateral
            Posicion areaDer = Constantes.centroArcoInf.moverPosicion(Constantes.ANCHO_AREA_GRANDE/2, Constantes.LARGO_AREA_GRANDE);
            Posicion areaIzq = Constantes.centroArcoInf.moverPosicion(-Constantes.ANCHO_AREA_GRANDE/2, Constantes.LARGO_AREA_GRANDE);
            int indiceRivalCercaAreaDer = areaDer.indiceMasCercano(rivales);
            int indiceRivalCercaAreaIzq = areaIzq.indiceMasCercano(rivales);
            
            movimientos[indiceLaterales[0]] = getPosicionCubrir(rivales[indiceRivalCercaAreaIzq],balon);
            movimientos[indiceLaterales[1]] = getPosicionCubrir(rivales[indiceRivalCercaAreaDer],balon);
            if (areaDer.distancia(movimientos[indiceLaterales[1]])>DISTANCIA_ALEJAMIENTO_COBERTURA) movimientos[indiceLaterales[1]]= areaDer;
            if (areaIzq.distancia(movimientos[indiceLaterales[0]])>DISTANCIA_ALEJAMIENTO_COBERTURA) movimientos[indiceLaterales[0]]= areaIzq;
                    
    	}
    	
    	return movimientos;
    }
    
    

    public static Posicion[] getMovimientoDelanteros(int[] indiceDelanteros, boolean atacando, Posicion balon, Posicion[] misJugadores, Posicion[] rivales) {
    	Posicion [] movimientos = new Posicion[11];
        
        
        
        return movimientos;
    }
    
    private static Posicion getPosicionCubrir(Posicion rival, Posicion balon) 
    {
        double dy = rival.getY();
        double dx = rival.getX();
        if(balon.getY() < dy) dy -= 2;
        else dy += 2;
        if(balon.getX() < dx) dx -= 2;
        else dx += 2;
        return new Posicion(dx, dy);
    }
}
